package com.xiekong.rpc.client;

import com.xiekong.rpc.bean.RpcRequest;
import com.xiekong.rpc.bean.RpcResponse;
import com.xiekong.rpc.codec.RpcDecoder;
import com.xiekong.rpc.codec.RpcEncoder;
import com.xiekong.rpc.handler.RpcClientHandler;
import com.xiekong.rpc.handler.RpcFuture;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * RPC 客户端（用于发送 RPC 请求）
 * @author XieKong
 */
public class RpcClient {
    private static final Logger logger = LoggerFactory.getLogger(RpcClient.class);
    private final String host;
    private final int port;

    public RpcClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public RpcResponse send(RpcRequest request) throws Exception {
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(workerGroup);
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    // 编码RPC请求
                    ch.pipeline().addLast(new RpcEncoder(RpcRequest.class));
                    // 解码RPC响应
                    ch.pipeline().addLast(new RpcDecoder(RpcResponse.class));
                    // 处理RPC响应
                    ch.pipeline().addLast(new RpcClientHandler());
                }
            });
            // 连接RPC服务器
            ChannelFuture future = bootstrap.connect(host, port).sync();
            // 写入RPC请求数据并关闭连接
            future.channel().writeAndFlush(request);
            RpcFuture rpcFuture = new RpcFuture(request);
            future.channel().closeFuture().sync();
            // 返回RPC响应对象
            return rpcFuture.getResponseResult();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }
}
